package edu.unika.aifb.graphindex.query;

/**
 * Copyright (C) 2009 G�nter Ladwig (gla at aifb.uni-karlsruhe.de)
 * 
 * This file is part of the graphindex project.
 *
 * graphindex is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License, version 2
 * as published by the Free Software Foundation.
 * 
 * graphindex is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with graphindex.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import edu.unika.aifb.graphindex.model.IEntity;
import edu.unika.aifb.graphindex.searcher.keyword.model.KeywordElement;
import edu.unika.aifb.graphindex.util.Util;

public class QNode implements Comparable<QNode>,Cloneable, Serializable {
	private static final long serialVersionUID = 8160044007993636653L;
	
	private String m_label;
	private boolean m_isSelectVariable;
	private KeywordElement keywordElement;
	private double maxScore = 0;
	private Iterator<IEntity> entityIterator;
	private Map<IEntity, Map<QNode, List<IEntity>>> seenEntities = new HashMap<IEntity, Map<QNode,List<IEntity>>>();
	private IEntity currentEntity;
	private IEntity topEntity = null;
	
	public QNode(String label) {
		m_label = label;
	}
	
	public QNode(KeywordElement keywordElement) {
		m_label = keywordElement.getUri();
		this.keywordElement = keywordElement;
	}
	
	public String getLabel() {
		return m_label;
	}
	
	public void setLabel(String label){
		m_label = label;
	}
	
	public boolean isVariable() {
		return Util.isVariable(getLabel());
	}
	
	public boolean isConstant() {
		return Util.isConstant(getLabel());
	}

	public int compareTo(QNode o) {
		return m_label.compareTo(o.getLabel());
	}

	public void setSelectVariable(boolean b) {
		m_isSelectVariable = b;
	}
	
	public boolean isSelectVariable() {
		return m_isSelectVariable;
	}
	
	public KeywordElement getKeywordElement() {
		return keywordElement;
	}

	public void setKeywordElement(KeywordElement keywordElement) {
		this.keywordElement = keywordElement;
}
	
	public boolean isKeywordNode(){
		return (keywordElement != null) && (keywordElement.entities != null) &&(!keywordElement.entities.isEmpty());
	}
	
	public double getMaxScore(){
		return maxScore;
	}
	
	public void setMaxScore(double maxScore){
		this.maxScore = maxScore;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((m_label == null) ? 0 : m_label.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		QNode other = (QNode)obj;
		if (m_label == null) {
			if (other.m_label != null)
				return false;
		} else if (!m_label.equals(other.m_label))
			return false;
		return true;
	}
	
	public String toString() {
		if(isKeywordNode())
			return m_label + "[" +  keywordElement.entities.size()+"]";
		return m_label;	
	}

	public Object clone() {
		QNode node = new QNode(getLabel());
		node.setSelectVariable(isSelectVariable());
		return node;
	}
	
	public IEntity getNextEntity(){
		if(keywordElement != null){
			if(entityIterator == null)
				entityIterator = keywordElement.entities.iterator();
			if(entityIterator.hasNext()){
				currentEntity = entityIterator.next(); 
				return currentEntity;
			}
		}
		return null;
	}
	
	public boolean hasMoreEntities(){
		if(isKeywordNode()){
			if(entityIterator == null)
				entityIterator = keywordElement.entities.iterator();
			return entityIterator.hasNext();
		}
		return false;
	}

	public IEntity getCurrentEntity() {
		return currentEntity;
	}

	public IEntity getTopEntity() {
		if(topEntity == null && isKeywordNode())
			topEntity = keywordElement.entities.iterator().next();
		return topEntity;
	}
	
	public IEntity getEntity(String entityUri){
		return keywordElement.entityUri2Entity.get(entityUri);
	}
	
	public void putSeenEntity(IEntity myEntity){
		seenEntities.put(myEntity, new HashMap<QNode, List<IEntity>>());
	}
	
	public void putSeenEntity(IEntity entity, QNode connectedNode, IEntity connectedEntity){
		Map<QNode, List<IEntity>> node2connectedEntities = seenEntities.get(entity);
		if(node2connectedEntities == null){
			node2connectedEntities = new HashMap<QNode, List<IEntity>>();
			seenEntities.put(entity, node2connectedEntities);
		}
		List<IEntity> connectedEntites =  node2connectedEntities.get(connectedNode);
		if(connectedEntites == null){
			connectedEntites = new ArrayList<IEntity>();
			node2connectedEntities.put(connectedNode, connectedEntites);
		}
		if(!connectedEntites.contains(connectedEntity))
			connectedEntites.add(connectedEntity);

	}
	
	public Map<IEntity, Map<QNode, List<IEntity>>> getSeenEntitiesMap(){
		return seenEntities;
	}
	
	public boolean isEntityProcessed(IEntity entity){
		Map<QNode, List<IEntity>> connectedEntities = seenEntities.get(entity);
		if(connectedEntities == null || connectedEntities.keySet().size() <= 1)
			return false;
		return true;
	}
}
